/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package x10.interfaces.cm15a.receive;

import java.util.BitSet;
import x10.enums.Device;
import x10.enums.Function;
import x10.enums.House;
import x10.enums.Interfaces;
import x10.enums.Media;
import x10.event.X10Command;
import x10.event.X10Event;
import x10.utilities.BitSetUtils;
import x10.utilities.ChunkOfBytes;

/**
 *
 * @author Denny
 */
public class PLMessageFactory extends X10DeviceReceiver{

    byte[] message;
    X10Command lastCommand = null;
    BitSet headerBits;
    private int dataByteCountByte = 1;
    private int headerByte = 2;
    private int addressByte;    //varies based on length of message
    private int dimBrightByte = 3;
    private int addressFunctionBit = 7;
    private int dimBrightBit = 6;

    public PLMessageFactory(LastAddressedTracker lat, Interfaces interfaceType){
        super(lat, interfaceType);
    }

    public X10Event process(ChunkOfBytes bytes){
        this.message = bytes.getBytes();
        addressByte = getDataByteCount() + 1;
        headerBits = BitSetUtils.byteToBitSet(message[headerByte]);

        //TODO: examine the standard/extended bit of the header
        // and call the corresponding method.  Only standard command
        // parsing is currently implemented

        return parseStandardCommand();
    }

    public X10Command parseStandardCommand(){
        X10Command x10Command = null;
        
        //Last Addressed Tracker keeps track power two-part powerline messages
        //The address is pushed to the LAT, and then, when the function part
        //arrives, it is coupled with the address to form a complete X10Command
        if(isAddress()){ //Set the last Addressed method and discard the rest
            lat.setLastAddressed(getHouseCode(), getDeviceCode());
        } else if (isFunction() || isDimBright()){
            House houseCode = getHouseCode();
            x10Command = new X10Command(houseCode, lat.getLastAddressed(houseCode), getFunctionCode(), getDimBrightLevel(), Media.POWERLINE, Interfaces.CM15A.toString());
        }
        return x10Command;
    }

    public House getHouseCode(){
        int houseCode = (int)BitSetUtils.getNibble(message[addressByte], "UPPER", "LOWER");
        return House.getHouseFromPowerline(houseCode);
    }

    public Device getDeviceCode(){
        Device retDevice = null;

        if(isAddress()){
            int deviceCode = (int)BitSetUtils.getNibble(message[addressByte], "LOWER", "LOWER");
            retDevice = Device.getDeviceFromPowerline(deviceCode);
        } else {
            retDevice = Device.DUNK;
        }
        return retDevice;
    }

    public Function getFunctionCode(){
        Function retFunction = null;

        if(isFunction() || isDimBright()){
            int functionCode = (int)BitSetUtils.getNibble(message[addressByte], "LOWER", "LOWER");
            retFunction = Function.getFunction(functionCode);
        } else {
            retFunction = Function.UNKNOWN;
        }
        return retFunction;
    }

    public int getDimBrightLevel(){
        if(isDimBright()){
            return message[dimBrightByte];
        } else {
            return 0;
        }
    }

    private boolean isAddress(){
        if(!headerBits.get(addressFunctionBit) && !isDimBright()){
            return true;
        } else {
            return false;
        }
    }

    private boolean isFunction(){
        if(headerBits.get(addressFunctionBit) && !isDimBright()){
            return true;
        } else {
            return false;
        }
    }

    private boolean isDimBright(){
        if(headerBits.get(dimBrightBit)){
            return true;
        } else {
            return false;
        }
    }

    private int getDataByteCount(){
        return (int)message[dataByteCountByte];
    }

}
